/**
 * Created by spatra on 14-5-7.
 */

/*
    通过中介对象，模拟传统面向对象语言的类继承（YUI库中使用的方法）
 */
function extend(child, parent){
    var agent = function(){};

    agent.prototype = parent.prototype;
    child.prototype = new agent();
    child.prototype.constructor = child;
    child.uber = parent.prototype;
}

/*
    置换算法的父类
 */
function swapMethod(){
    alert('内部错误，此类不应实例化！');
}

swapMethod.prototype = {
    constructor: swapMethod,
    commonInit: function(methodName, proPhyPage){
        this.methodName = methodName;
        this.proPhyPage = proPhyPage;
        this.proPhyPageArray = new Array();
        this.missingCounter = 0;

        this.theMethodDiv = createMethodDiv(methodName, proPhyPage);
        $('#simulation').append( this.theMethodDiv );
    },
    findPageById: function(pageId){
        for(var i = 0; i < this.proPhyPageArray.length; ++i )
            if( pageId == this.proPhyPageArray[i] )
                return true;
        return false;
    }
};

/*----------End of swapMethod-----------------*/

/*
    此类对应先进先出算法
 */

function swapFIFO(proPhyPage){
    this.commonInit('先进先出置换算法', proPhyPage);
}

extend(swapFIFO, swapMethod);

swapFIFO.prototype.schedule = function(pageId){
    if( this.findPageById(pageId) ){
        addColumn(this.theMethodDiv);
        return;
    }

    this.missingCounter++;
    addColumn(this.theMethodDiv, pageId, this.getEliminationPageId() );
    this.proPhyPageArray.unshift(pageId);
};

swapFIFO.prototype.getEliminationPageId = function(){
    if( this.proPhyPage > this.proPhyPageArray.length )
        return null;
    else
        return this.proPhyPageArray.pop();
};

/*---------------End of swapFIFO -------------*/

/*
    此类对应的最优置换算法。
 */
function swapOPT(proPhyPage, schedulingQueue){
    this.commonInit('最优置换算法', proPhyPage );
    this.currSchedulingPageIndex = -1;
    if( arguments.length == 1 )
        this.schedulingQueue = scheduleQueue.slice(0);
    else
        this.schedulingQueue = schedulingQueue.slice(0);
}

extend(swapOPT, swapMethod);

swapOPT.prototype.schedule = function(pageId){
   this.currSchedulingPageIndex++;

   if( this.findPageById(pageId) ){
       addColumn(this.theMethodDiv);
       return;
   }

    this.missingCounter++;
    addColumn(this.theMethodDiv, pageId, this.getEliminationPageId() );
    this.proPhyPageArray.unshift(pageId);

};

swapOPT.prototype.getEliminationPageId = function(){
    if( this.proPhyPage > this.proPhyPageArray.length )
        return null;

    var target = null;
    var maxIndex = -1;
    for(var i = 0; i < this.proPhyPageArray.length; ++i ){
        var notFound = true;
        for(var j = this.currSchedulingPageIndex + 1; j < this.schedulingQueue.length; ++j ){
            if( this.proPhyPageArray[i] == this.schedulingQueue[j] ){
                if( maxIndex < j )
                    maxIndex = j;
                notFound = false;
                break;
            }
        }

        if( notFound ) {
            target = this.proPhyPageArray[i];
            break;
        }
    }

    if( target != null ) {
        console.log('NotNULL' + target );
        return removeInArray(this.proPhyPageArray, target);
    }
    else
        return removeInArray(this.proPhyPageArray, this.schedulingQueue[maxIndex] );
};

/*-------------------End of swapOPT-------------------*/

/*
    此类对应最近最少用置换算法
 */

function swapLRU(proPhyPage){
    this.commonInit('最近最少用置换算法', proPhyPage);
}

extend(swapLRU, swapMethod);

function LRUPhyPage(pageId) {
    this.pageId = pageId;
    this.refCounter = 1;
}

swapLRU.prototype.schedule = function(pageId){
    if( this.findPageById(pageId) ){
        addColumn( this.theMethodDiv );
        return;
    }

        this.missingCounter++;
        addColumn(this.theMethodDiv, pageId, this.getEliminationPageId() );
        this.proPhyPageArray.unshift( new LRUPhyPage(pageId) );

};

swapLRU.prototype.findPageById = function(pageId){
    for(var i = 0; i < this.proPhyPageArray.length; ++i )
        if( pageId == this.proPhyPageArray[i].pageId ) {
            this.proPhyPageArray[i].refCounter++;
            return true;
        }
    return false;
};
swapLRU.prototype.getEliminationPageId = function(){
    if( this.proPhyPage > this.proPhyPageArray.length )
        return null;

    var minRefCounterIndex  = 0;
    for(var i = 1; i < this.proPhyPageArray.length; ++i ){
        if( this.proPhyPageArray[i].refCounter < this.proPhyPageArray[minRefCounterIndex].refCounter )
            minRefCounterIndex = i;
    }

    var targetPageId = this.proPhyPageArray[ minRefCounterIndex ].pageId;
    this.proPhyPageArray.splice(minRefCounterIndex, 1);
    this.resetRefCounter();
    return targetPageId;
};

swapLRU.prototype.resetRefCounter = function(){
    for(var i = 0; i < this.proPhyPageArray.length; ++i )
        this.proPhyPageArray[i].refCounter = 0;
};

/*-------------------End of swapLRU-------------------*/